package game;

import ai.AI_Controller;
import ai.PubevalAI;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;

/**
 *
 * @author group19
 * This class will manipulate the existing commands
 * Make gaming environment
 * 
 */
public class Controller {
    
    private final int BENCHMARK_ROUNDS = 1000;

    private BGBoard board;
    private boolean play = true;
    AI_Controller AI;
    AI_Controller RANDOM_AI;
    AI_Controller pubeval;

    public Controller() {
        board = new BGBoard();
        //AI = new AI_Controller(AI_Controller.load("AI_Latest"));
       // AI = new AI_Controller(false); // default!
        pubeval = new AI_Controller(new PubevalAI());
    }

    // Game start human vs Neural
    public void start() {

        showIntroduction();
        board.initializeBoard();

        AI.getANN().setPlayer(BGBoard.BLACK);
        board.setPlayer_black("ANN");
        board.setPlayer_white("Human");

        // with turn
        while (play) {
            board.diceRoll();
            printBoard();
            board.GetPossiblePositions();
            
            int nrOfMoves = 2;
            if (board.getDice()[0] == board.getDice()[1]) {
                nrOfMoves = 4;
            }
                
            if (board.whosMove == BGBoard.WHITE) {
                for (int i = 0; i < nrOfMoves; i++) {
                    commandLinePlayer();
                }
            } else {
                doMoves(board, AI, nrOfMoves);
            }
            
            // check if there is a winner
            if (board.isReadyBlack() || board.isReadyWhite()) {
                if (board.checkWinner()) {
                    announceWinner(board.getWinner());
                    break;
                }
            }

            board.changePlayer();
        }
    }

    // Train ann
    public void startAI(int nrOfTrainingMatches) {

        showIntroduction();
        int AITotalWins = 0;
        int AIrandomTotalWins = 0;
        int AIWinsForMatch = 0;
        int AIrandomWinsForMatch = 0;
        boolean win;
        int matches = 0;
        int adjusts = 0;

        AI.getANN().setPlayer(BGBoard.BLACK);

        RANDOM_AI = new AI_Controller(true);

        while (matches < nrOfTrainingMatches) {
            board = new BGBoard();
            board.setPlayer_black("ANN");
            board.setPlayer_white("Random_ANN");
            board.initializeBoard();

            win = false;
            // with turn
            while (!win) {
                board.diceRoll();
                //printBoard();
                board.GetPossiblePositions();

                int nrOfMoves = 2;
                if (board.getDice()[0] == board.getDice()[1]) {
                    nrOfMoves = 4;
                }
                
                if (board.whosMove == BGBoard.WHITE) {
                    doMoves(board, RANDOM_AI, nrOfMoves);
                } else {
                    doMoves(board, AI, nrOfMoves);
                }

                // check if there is a winner
                if (board.isReadyBlack() || board.isReadyWhite()) {
                    if (board.checkWinner()) {
                        announceWinner(board.getWinner());
                        System.out.println(board);
                        if (board.getWinner() == BGBoard.WHITE) {
                            AIrandomTotalWins++;
                            AIrandomWinsForMatch++;
                        } else {
                            AITotalWins++;
                            AIWinsForMatch++;
                        }

                        win = true;
                        
                        if (AIWinsForMatch > 3) {
                            matches++;
                            AIrandomWinsForMatch = 0;
                            AIWinsForMatch = 0;
                            RANDOM_AI = new AI_Controller(true);
                        }
                        else if (AIrandomWinsForMatch > 6) {
                            AI.getANN().adjust(RANDOM_AI.getANN().getInWeights(),
                                               RANDOM_AI.getANN().getOutWeights(), 
                                               RANDOM_AI.getANN().getThresholds());
                        
                            adjusts++;
                            matches++;
                            AIrandomWinsForMatch = 0;
                            AIWinsForMatch = 0;                            
                            RANDOM_AI = new AI_Controller(true);
                        }
                    }
                }

                board.changePlayer();
            }
            AI.getANN().incrementGamesPlayed();
            System.out.println("AI champion wins: " + AITotalWins);
            System.out.println("AI random wins: " + AIrandomTotalWins);
            System.out.println("Matches: " + matches);
            System.out.println("Adjusts: " + adjusts);
            System.out.println();
            System.out.println();
        }
        
        AI.write("AI" + AI.getANN().getNrOfAdjusts());
        AI.write("AI_Latest");

        System.out.println("AI champion wins: " + AITotalWins);
        System.out.println("AI random wins: " + AIrandomTotalWins);
        System.out.println("ANN trained: " + AI.getANN().getNrOfAdjusts());
        System.out.println("ANN played Game: " + AI.getANN().getNrOfGamesPlayed());

    }

    /*
     * Bechmark with Pubeval
     */
    public void startAIpub() {

        showIntroduction();
        int AI_Wins = 0;
        int PubWins = 0;

        AI.getANN().setPlayer(BGBoard.WHITE);

        for (int j = 0; j < BENCHMARK_ROUNDS; j++) {
            board = new BGBoard();
            board.setPlayer_white("ANN");
            board.setPlayer_black("Pubeval");
            board.initializeBoard();
            // with turn
            while (true) {
                board.diceRoll();
                //printBoard();
                board.GetPossiblePositions();
                
                int nrOfMoves = 2;
                if (board.getDice()[0] == board.getDice()[1]) {
                    nrOfMoves = 4;
                }
                
                if (board.whosMove == BGBoard.WHITE) {
                    doMoves(board, AI, nrOfMoves);
                } else {
                    doMoves(board, pubeval, nrOfMoves);
                }

                // check if there is a winner
                if (board.isReadyBlack() || board.isReadyWhite()) {
                    if (board.checkWinner()) {
                        announceWinner(board.getWinner());
                        System.out.println(board);
                        if (board.getWinner() == BGBoard.WHITE) {
                            AI_Wins++;
                        } else {
                            PubWins++;
                        }
                        break;
                    }
                }

                board.changePlayer();
            }

        }

        System.out.println("AI champion won: " + AI_Wins);
        System.out.println("AI pub won: " + PubWins);

    }

    /*
     * pub pub
     */

   public void startPubPub() {

        showIntroduction();
        int AI_Wins = 0;
        int PubWins = 0;

       // AI.getANN().setPlayer(BGBoard.WHITE);

        for (int j = 0; j < BENCHMARK_ROUNDS; j++) {
            board = new BGBoard();
            board.setPlayer_white("Pubeval");
            board.setPlayer_black("Pubeval");
            board.initializeBoard();
            // with turn
            while (true) {
                board.diceRoll();
                //printBoard();
                board.GetPossiblePositions();

                int nrOfMoves = 2;
                if (board.getDice()[0] == board.getDice()[1]) {
                    nrOfMoves = 4;
                }

                if (board.whosMove == BGBoard.WHITE) {
                    doMoves(board, pubeval, nrOfMoves);
                } else {
                    doMoves(board, pubeval, nrOfMoves);
                }

                // check if there is a winner
                if (board.isReadyBlack() || board.isReadyWhite()) {
                    if (board.checkWinner()) {
                        announceWinner(board.getWinner());
                        System.out.println(board);
                        if (board.getWinner() == BGBoard.WHITE) {
                            AI_Wins++;
                        } else {
                            PubWins++;
                        }
                        break;
                    }
                }

                board.changePlayer();
            }

        }

        System.out.println("AI Pub WHITE: " + AI_Wins);
        System.out.println("AI pub BLACK: " + PubWins);

    }

   
    private void doMoves(BGBoard board, AI_Controller ai, int nrOfMoves) {
        board.GetPossiblePositions();
        ArrayList<byte[]> moves = ai.makemoves((BGBoard) board.clone());
        for (int i = 0; i < nrOfMoves; i++) {
            if (moves.size() > i) {
                board.applyMove(moves.get(i)[0], moves.get(i)[1]);
            }
        }
    }

    /*
     * Per dice turn
     */
    private void commandLinePlayer() {
        board.GetPossiblePositions();
        if (!board.getMoves().isEmpty()) { // if there are possible moves!	
            board.showPossiblePositions();
            byte[] applyMove;
            applyMove = getCommandMove();
            board.applyMove(applyMove[0], applyMove[1]);
            board.PrintWhiteBlack();
            printBoard();
        }
    }

    /*
     * Per dice turn
    
    private void computerAI(){
    board.GetPossiblePositions();
    if (!board.getMoves().isEmpty()){ // if there are possible moves!		
    // AI test
    board.showPossiblePositions();
    byte[] applyMove = AI.makemoves((BGBoard)board.clone());
    System.out.print("AI moved! :");
    for (int i = 0; i < applyMove.length; i++) {
    System.out.print(applyMove[i]+" ");
    }
    System.out.println();
    board.applyMove(applyMove[0], applyMove[1]);		
    board.PrintWhiteBlack();
    printBoard();
    }
    }*/
    /*
     * Help methods
     */
    /*
     * Playing commands
     */
    public byte[] getCommandMove() {
        while (true) {
            System.out.print("Command> ");
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            try {
                String line = br.readLine();
                String[] lines = line.split(" ");
                for (int i = 0; i < board.getMoves().size(); i++) {
                    if (board.getMoves().get(i)[0] == Byte.valueOf(lines[0])
                            && board.getMoves().get(i)[1] == Byte.valueOf(lines[1])) {
                        return new byte[]{Byte.valueOf(lines[0]), Byte.valueOf(lines[1])};
                    }
                }
                System.out.println("Illegal move!");
            } catch (Exception ioe) {
                System.out.println("Write something readable!");
            }
        }
    }

    /*
     * Command methods
     * Display methods!
     * add
     * add
     */
    public void printBoard() {

        System.out.println(board.getWhoMoveVerbose() + "'s turn:");
        System.out.println("1st die is: " + BGBoard.dieString(board.getDice()[0]));
        System.out.println("2nd die is: " + BGBoard.dieString(board.getDice()[1]));
        //board.GetPossiblePositions();
        //board.showPossiblePositions();


        //board.printBoardArray();
        System.out.println(board);
    }
    /*
     * Announce the winner
     */

    public void announceWinner(boolean winner) {
        System.out.println((winner) ? "White wins!" : "Black wins!");
    }
    /*
     * Introduction manual!
     */

    public void showIntroduction() {
        System.out.println("Manual for developers \n"
                + "White(W) goes up and - integer and 0 belongs to it as a bar, 27 its winner bar"
                + "\nBlack(B) goes down and + integer 25 belongs to it as a bar, 26 its winner bar"
                + "\n1-24 board representation\n\n\n");
    }

    public void printAnn() {
    }
    //
}
